home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 January: Mac OS SDK / Dev.CD Jan 99 SDK2.toast / Development Kits / TEC 1.4 / SampleCode / UnicodeHub / Convert.cp next >
Encoding:
Text File  |  1998-09-25  |  39.0 KB  |  1,135 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        Convert.cp
  3.  
  4.     Contains:    
  5.  
  6.     Version:    System 8
  7.  
  8.     Copyright:    © 1997-1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Julio Gonzalez
  13.  
  14.         Other Contact:        Andrew Daniels
  15.  
  16.         Technology:            International
  17.  
  18.     Writers:
  19.  
  20.         (jag)    Julio Gonzalez
  21.  
  22.     Change History (most recent first):
  23.  
  24.       <TEC1>     6/16/98    jag        first checked in
  25.       <TEC0>     6/16/98    jag        Moved to BBS (new change numbers!).
  26.       
  27.     Old history in NRBuild:
  28.          <3>     8/22/97    jag        Fix yet another bug in ResolveConversionParams. Also better
  29.                                     usage of TECFlush.
  30.          <2>     8/20/97    jag        Fix bug in ResolveConversionParams and set output handle length
  31.                                     appropriately in the Catch segment of DoConvert.
  32. */
  33.  
  34. #include "UnicodeHub.h"
  35. #include "UnicodeHubConstants.h"
  36.  
  37. #include <Sound.h>
  38. #include <Script.h>                            // Script Manager definitions
  39.  
  40. #include <LGrowZone.h>
  41. #include <LWindow.h>
  42. #include <PP_Messages.h>
  43. #include <PP_Resources.h>
  44. #include <PPobClasses.h>
  45. #include <UDrawingState.h>
  46. #include <UMemoryMgr.h>
  47. #include <UReanimator.h>
  48. #include <UDesktop.h>
  49. #include <URegistrar.h>
  50. #include <LEditField.h>
  51. #include <LTextEdit.h>
  52. #include <UTextTraits.h>
  53. #include "LDynamicArray.h"
  54.  
  55.  
  56.     /**********************************************************************************************************
  57.      *    TEC SPECIFIC CODE COMMENT
  58.      *
  59.      *    When using either the Text Encoding Converter or the Unicode Converter, it is wise to set a minimum output
  60.      *    buffer of 32 bytes.  Some conversions might convert a single element in one encoding to 32 bytes in the
  61.      *    other encoding.  32 bytes is currently the maximum that TEC with convert a single element to another
  62.      *    encoding.
  63.      **********************************************************************************************************/
  64. #define kMinimumBufferSize 32
  65.  
  66.     /**********************************************************************************************************
  67.      *    TEC SPECIFIC CODE COMMENT
  68.      *
  69.      *    NeedsTag inserts one of the language (CJK) character tags that we have placed in Apple's corporate zone.
  70.      *    We use it when we convert from Styled Text to Unicode in order to achieve Round Trip in our conversions.
  71.      *    If we know that the encoding we are about to convert is Chinese, Korean, or Japanese, then we insert
  72.      *    the appropriate tag in the Unicode stream.  Note, there are tags for both UTF-16 and UTF-8.
  73.      **********************************************************************************************************/
  74.  
  75. static void NeedsTag( StringPtr tag, TextEncoding  theEncoding, TextEncoding unicodeEncoding )
  76. {
  77.     TextEncodingBase    base=::GetTextEncodingBase( theEncoding );
  78.     
  79.     *tag=0;
  80.     
  81.     if( ::GetTextEncodingFormat(unicodeEncoding) == kUnicodeUTF8Format )
  82.     {        
  83.         switch( base )    //UTF-8 Tags
  84.         {
  85.             case    kTextEncodingMacJapanese:        tag[3]=0x9E; break;
  86.             case    kTextEncodingMacChineseTrad:    tag[3]=0x9D; break;
  87.             case    kTextEncodingMacKorean:            tag[3]=0x9F; break;
  88.             case    kTextEncodingMacChineseSimp:    tag[3]=0x9C; break;
  89.             default:                                tag[3]=0;
  90.         }
  91.         
  92.         if( tag[3] )
  93.         {
  94.             tag[0]=3;
  95.             tag[1]=0xEF;
  96.             tag[2]=0xA1;
  97.         }
  98.     }
  99.     else                    //UTF-16 Tags
  100.     {
  101.         switch( base )
  102.         {
  103.             case    kTextEncodingMacJapanese:        tag[2]=0x5E; break;
  104.             case    kTextEncodingMacChineseTrad:    tag[2]=0x5D; break;
  105.             case    kTextEncodingMacKorean:            tag[2]=0x5F; break;
  106.             case    kTextEncodingMacChineseSimp:    tag[2]=0x5C; break;
  107.             default:                                tag[2]=0;
  108.         }
  109.         
  110.         if( tag[2] )
  111.         {
  112.             tag[0]=2;
  113.             tag[1]=0xF8;
  114.         }
  115.     }
  116.     
  117. }
  118.     /**********************************************************************************************************
  119.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  120.      **********************************************************************************************************/
  121.  
  122.  
  123. // ---------------------------------------------------------------------------------
  124. //        • ResizeOutputHandle
  125. //        
  126. //        This function increase the size of a locked handle by resizeBy and will
  127. //        keep update a pointer into the handle if it happens to move after the resize
  128. //        We'll just this routine in the convert methods when we run out of buffer
  129. //        space and need to make room for more output
  130. // ---------------------------------------------------------------------------------
  131.  
  132. void ResizeOutputHandle( Handle h, char** outputPtr, ByteCount resizeBy );
  133. void ResizeOutputHandle( Handle h, char** outputPtr, ByteCount resizeBy )
  134. {
  135.     UInt32    oldSize=(UInt32)(*outputPtr) - (UInt32)(*h);
  136.     
  137.     ::HUnlock( h);
  138.     ::SetHandleSize( h, GetHandleSize( h) + resizeBy);
  139.     ThrowIfMemError_();
  140.     
  141.     ::HLock( h);
  142.     *outputPtr=(char*)( (UInt32)(*h) + oldSize);
  143. }
  144.  
  145. // ---------------------------------------------------------------------------------
  146. //        • ConvertFromMulti
  147. //        
  148. //        This method will convert Styled Text into a stream of Unicode.  Input is
  149. //        a text handle and a style record handle.  Based on each one of the runs
  150. //        found in the style handle, a conversion will take place from the appropriate
  151. //        text encoding derived from the script run to unicode.  Offsets into the 
  152. //        unicode stream will be kept so on output, we'll have a handle with a stream
  153. //        of unicode ( converted to hex - since we can't display Unicode directly
  154. //        yet :-)  and a offset array indicating were in the unicode stream the original
  155. //        script runs from the styled text occur.
  156. // ---------------------------------------------------------------------------------
  157.  
  158.  
  159. OSStatus
  160. CPPStarterApp::ConvertFromMulti(  TextEncoding unicodeEncoding, const Handle fromHexText, TEStyleHandle theStyle, UInt32 fromLen,
  161.                             Handle &toHexText, ByteCount &inputRead, ByteCount &outputLen,
  162.                              ByteCount &toLen, ByteOffset** &theOffsets,
  163.                              UInt32 toUnicodeFlags)
  164. {
  165.     TextToUnicodeInfo    textToUnicodeInfo;
  166.     OSStatus            status=noErr;
  167.     char*                input;
  168.     char*                output;
  169.     UnicodeMapping        mapping;
  170.     ByteCount            origOutputLen;
  171.     
  172.     inputRead=0;
  173.     outputLen=0;
  174.     toLen=0;
  175.     
  176.     UInt16    noRuns=(**theStyle).nRuns;
  177.     
  178.     //Create an array of offsets that is the same size as the number of runs in the styled text
  179.     //This offset array will be used by the caller to show how each run in the style run matches
  180.     //the Unicode stream. 
  181.     theOffsets=(ByteOffset**)NewHandle( noRuns * sizeof(ByteOffset) );
  182.     if( theOffsets == NULL )
  183.     {
  184.         status=MemError();
  185.         return status;
  186.     }
  187.     
  188.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  189.     outputLen=::GetHandleSize( toHexText );
  190.     if( outputLen < kMinimumBufferSize )
  191.     {
  192.         outputLen=kMinimumBufferSize;
  193.         ::SetHandleSize(toHexText, outputLen);
  194.     }
  195.     origOutputLen=outputLen;
  196.     
  197.     ::HLock( fromHexText);
  198.     input=*fromHexText;
  199.     
  200.     ::HLock( toHexText);
  201.     output=*toHexText;
  202.     
  203.  
  204.     //Fill out the unicode mapping structure with the appropriate version of Unicode ( UTF-8 or UTF-16)
  205.     mapping.unicodeEncoding = unicodeEncoding;
  206.     mapping.mappingVersion = kUnicodeUseLatestMapping;
  207.     
  208.     //loop for every one of the runs in our styled text and convert each run to Unicode
  209.     int i;
  210.     for(i=0; i<noRuns && status==noErr; i++) 
  211.     {
  212.         Str31            fontName;
  213.         unsigned char    tag[4];
  214.         
  215.         short    index=(**theStyle).runs[i].styleIndex;
  216.         
  217.     /**********************************************************************************************************
  218.      *    TEC SPECIFIC CODE COMMENT
  219.      *
  220.      *    In order to get an encoding for the specific run in the Styled Text, we call UpgradeScriptInfoToTextEncoding
  221.      *    with the font name only.  This is all we need to get an encoding.  We'll create our conversion context
  222.      *    based on this encoding
  223.      **********************************************************************************************************/
  224.         ::GetFontName( (*((**theStyle).styleTab))[index].stFont, fontName );
  225.         
  226.         /* If GetFontName fails by returning an empty font name ( possibly due to a bug in the Font itself ),
  227.             then call FontToScript and use the Script to derive the Text Encoding.  I've seen this bug
  228.             occur on Fonts present in older versions of the Hebrew Language Kit */
  229.         if( *fontName )
  230.             status=::UpgradeScriptInfoToTextEncoding( kTextScriptDontCare,
  231.                 kTextRegionDontCare, kTextLanguageDontCare, fontName, &mapping.otherEncoding);
  232.         else
  233.             status=::UpgradeScriptInfoToTextEncoding( ::FontToScript((*((**theStyle).styleTab))[index].stFont),
  234.                 kTextRegionDontCare, kTextLanguageDontCare, NULL, &mapping.otherEncoding);
  235.         if( status )
  236.             break;
  237.             
  238.             
  239.         status=::CreateTextToUnicodeInfo( &mapping, &textToUnicodeInfo );
  240.     /**********************************************************************************************************
  241.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  242.      **********************************************************************************************************/
  243.         if( !status )
  244.         {
  245.             ByteCount    oSourceRead=0;
  246.             ByteCount    oUnicodeLen=0;
  247.             
  248.             //assertain the input buffer length from the size of the style run
  249.             ByteCount    inputLen= ( i == noRuns-1 ? fromLen : (**theStyle).runs[i+1].startChar ) -
  250.                                 (**theStyle).runs[i].startChar    ;
  251.                                         
  252.     
  253.     
  254.             //figure out if we need a language tag.  If so, insert it in the output stream.
  255.             NeedsTag( tag, mapping.otherEncoding, unicodeEncoding );
  256.             if( *tag )
  257.             {
  258.                 if(*tag > outputLen )
  259.                 {
  260.                     ResizeOutputHandle( toHexText, &output, origOutputLen );
  261.                     outputLen+=origOutputLen;
  262.                 }
  263.                 
  264.                 ::BlockMove( tag+1, output, *tag );
  265.                 output+=*tag;
  266.                 outputLen-=*tag;
  267.             }
  268.             
  269.             
  270.             char*        oInput=input;
  271.             char*        oOutput=output;
  272.             
  273.     /**********************************************************************************************************
  274.      *    TEC SPECIFIC CODE COMMENT
  275.      *
  276.      *    Call ConvertFromTextToUnicode in a loop in the event that our output buffer is too small.  Each time
  277.      *    the call tells us that the buffer is too small, we just make the output buffer bigger by as much as it 
  278.      *    originally was.
  279.      **********************************************************************************************************/
  280.             do{
  281.                 ByteCount    tSourceRead, tUnicodeLen;
  282.                 
  283.                 status=::ConvertFromTextToUnicode( textToUnicodeInfo, 
  284.                                                 inputLen, oInput,
  285.                                                  toUnicodeFlags,
  286.                                                  0, NULL, NULL, NULL,
  287.                                                  outputLen, &tSourceRead, &tUnicodeLen, 
  288.                                                  (UniChar*)oOutput);
  289.                 if( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr )
  290.                 {
  291.                     //Increase the size of the output buffer and update our input and output pointers
  292.                     
  293.                     ResizeOutputHandle( toHexText, &oOutput, origOutputLen );
  294.                     oOutput=(char*)( (UInt32)oOutput + tUnicodeLen);
  295.                     outputLen=origOutputLen+(outputLen-tUnicodeLen);
  296.  
  297.                     oInput=(char*)( (UInt32)oInput + tSourceRead);
  298.                     inputLen-=tSourceRead;
  299.                 }
  300.                 else
  301.                     outputLen-=tUnicodeLen;
  302.  
  303.                 
  304.                 oSourceRead+=tSourceRead;
  305.                 oUnicodeLen+=tUnicodeLen;
  306.  
  307.             }while( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr );
  308.             
  309.     /**********************************************************************************************************
  310.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  311.      **********************************************************************************************************/
  312.  
  313.             //Now we have processed an entire run of text, so update our offsets accordingly
  314.             if( status == noErr || status == kTECUsedFallbacksStatus)
  315.             {
  316.             
  317.                 (*theOffsets)[i]=toLen;
  318.                 
  319.                 inputRead+=oSourceRead;
  320.                 toLen+=oUnicodeLen;    
  321.                 if( *tag )
  322.                     toLen+=*tag;
  323.                 
  324.                 input+=oSourceRead;
  325.                 output+=oUnicodeLen;
  326.                 
  327.                 
  328.                 status=noErr;
  329.             }
  330.             
  331.             
  332.             ::DisposeTextToUnicodeInfo( &textToUnicodeInfo );
  333.         }
  334.     
  335.  
  336.     }
  337.     
  338.     ::HUnlock( (Handle)toHexText );
  339.     ::SetHandleSize( (Handle)toHexText, toLen );
  340.     
  341.     outputLen=toLen;
  342.     
  343.     //This routine always shows the Unicode output stream in Hex, so go ahead an convert it
  344.         
  345.     if( toLen > 0 )
  346.     {
  347.         Handle    theHexText=::NewHandle(toLen*2);
  348.         ByteCount    destLen;
  349.         
  350.         if( theHexText )
  351.         {
  352.             HLock( toHexText);
  353.             HLock( theHexText);
  354.             BufToHex((StringPtr)*toHexText, (StringPtr)*theHexText, toLen, destLen, 0);
  355.             HUnlock( theHexText);
  356.         }
  357.         
  358.         ::DisposeHandle( toHexText );
  359.         toHexText=theHexText;
  360.         toLen*=2;
  361.         
  362.         ::HUnlock( fromHexText );
  363.         for(i=i-1; i>=0; i--)
  364.             (*theOffsets)[i]*=2;
  365.     }
  366.     
  367.     return status;
  368. }
  369.  
  370.     /**********************************************************************************************************
  371.      *    TEC SPECIFIC CODE COMMENT
  372.      *
  373.      *    This code tests to see if the encoding is Unicode.  The Block from 0x100 to 0x1FF has been currently
  374.      *    reserved for Unicode encodings.   In the future there is a small possibility that this might change.
  375.      *    If you require this type of functionality in your Apps, please notify us so that we may provide a 
  376.      *    suitable API for you to use.
  377.      **********************************************************************************************************/
  378. Boolean 
  379. CPPStarterApp::IsUnicode( TextEncoding encoding )
  380. {
  381.     TextEncoding    encodingBase=::GetTextEncodingBase( encoding );
  382.     
  383.     if( encodingBase >= kTextEncodingUnicodeDefault && encodingBase <= 0x01FF )
  384.         return true;
  385.     
  386.     return false;
  387. }
  388.     /**********************************************************************************************************
  389.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  390.      **********************************************************************************************************/
  391.  
  392. // ---------------------------------------------------------------------------------
  393. //        • ResolveConversionParams
  394. //        
  395. //        This method turns a selection from our pop up menus into the appropriate
  396. //        text encodings.  Later it determines which converter to use to perform the
  397. //        conversion.  Either the Unicode Converter or the Text Encoding Converter.
  398. //        Remember, this sample application code show cases the Unicode Converter.
  399. //        Hence, it tries to do as much as it can in the Unicode Converter.  This might
  400. //        not be wise in your own applications as the Text Encoding Converter might
  401. //        be able to perform a conversion more efficiently than the Unicode Converter.
  402. //        Especially if there exists a plugin that can go from encoding x to encoding y
  403. //        directly.  The Unicode Converter on the other hand has to use Unicode as
  404. //        a hub.  Wouldn't you rather get a direct flight to your destination? :-)
  405. // ---------------------------------------------------------------------------------
  406. void
  407. CPPStarterApp::ResolveConversionParams(    UInt32    fromEncodingIndex,  TextEncoding *fromTextEncoding,
  408.                                         UInt32     toEncodingIndex,     TextEncoding *toTextEncoding,
  409.                                         int        *converterToUse )
  410. {
  411.     OSStatus        status;
  412.     UnicodeMapping    findMapping;
  413.     UnicodeMapping    foundMapping;
  414.     ItemCount        oActualCount;
  415.  
  416.     findMapping.mappingVersion=kUnicodeUseLatestMapping;
  417.  
  418.     if( fromTextEncoding )
  419.     {    
  420.         if( fromEncodingIndex != 0 )
  421.             *fromTextEncoding = gTheApp->mAvailableMappings[ fromEncodingIndex-1 ];
  422.         else
  423.             *fromTextEncoding=kTextEncodingMultiRun;
  424.     }
  425.  
  426.     if( toTextEncoding )
  427.     {
  428.         if( toEncodingIndex != 0 )
  429.             *toTextEncoding = gTheApp->mAvailableMappings[ toEncodingIndex-1 ];
  430.         else
  431.             *toTextEncoding=kTextEncodingMultiRun;
  432.     }
  433.  
  434.     if( converterToUse == NULL || fromTextEncoding == NULL || toTextEncoding == NULL)
  435.         return;
  436.     
  437.     if( *fromTextEncoding == *toTextEncoding )
  438.     {
  439.         *converterToUse = kIllegalConverter;
  440.         return;
  441.     }
  442.     
  443.     if(  IsUnicode( *fromTextEncoding ) )     //if the from encoding is unicode but not UTF7 then return unicode converter
  444.     {                                        //otherwise return the high level converter
  445.         if( ( ::GetTextEncodingFormat( *fromTextEncoding ) == kUnicodeUTF7Format ) ||  IsUnicode( *toTextEncoding) )
  446.             *converterToUse = kHighLevelConverter;
  447.         else
  448.         {
  449.             *converterToUse = kUnicodeConverter;
  450.             
  451.             //Find out if the Unicode Converter can handle the destination encoding
  452.             if( *toTextEncoding != kTextEncodingMultiRun )
  453.             {
  454.                 findMapping.unicodeEncoding=*fromTextEncoding;
  455.                 findMapping.otherEncoding=*toTextEncoding;
  456.                 
  457.                 status = ::QueryUnicodeMappings(kUnicodeMatchOtherBaseMask | kUnicodeMatchOtherVariantMask | kUnicodeMatchOtherFormatMask, 
  458.                     &findMapping, 1, &oActualCount, &foundMapping);
  459.                 
  460.                 if( ( status != noErr && status != kTECArrayFullErr ) || ( oActualCount == 0 ) )
  461.                 {
  462.                     *converterToUse = kHighLevelConverter;
  463.                     return;
  464.                 }
  465.             }
  466.         }
  467.     }
  468.     else if(  IsUnicode( *toTextEncoding) )     //if the from encoding is unicode but not UTF7 then return unicode converter
  469.     {                                            //otherwise return the high level converter
  470.         if( ( GetTextEncodingFormat( *toTextEncoding ) == kUnicodeUTF7Format ) ||  IsUnicode( *fromTextEncoding) )
  471.             *converterToUse = kHighLevelConverter;
  472.         else    
  473.         {
  474.             *converterToUse = kUnicodeConverter;
  475.             
  476.             //Find out if the Unicode Converter can handle the destination encoding
  477.             if( *fromTextEncoding != kTextEncodingMultiRun )
  478.             {
  479.                 findMapping.unicodeEncoding=*toTextEncoding;
  480.                 findMapping.otherEncoding=*fromTextEncoding;
  481.                 
  482.                 status = ::QueryUnicodeMappings(kUnicodeMatchOtherBaseMask | kUnicodeMatchOtherVariantMask | kUnicodeMatchOtherFormatMask, 
  483.                     &findMapping, 1, &oActualCount, &foundMapping);
  484.                 
  485.                 if( ( status != noErr && status != kTECArrayFullErr ) || ( oActualCount == 0 ) )
  486.                 {
  487.                     *converterToUse = kHighLevelConverter;
  488.                     return;
  489.                 }
  490.             }
  491.         }
  492.     }
  493.     else
  494.     {
  495.         //We've determined that neither encoding is in Unicode so go ahead an determine if we can use the Unicode Converter
  496.         //as a Hub ( fromEncoding->Unicode->toEncoding ).
  497.         
  498.         
  499.         //If either encoding is a MultiRun, then we can't use either converter to do the job since the Unicode converter
  500.         //can only convert to/from Unicode and we have already determined that neither encoding is unicode.  The high
  501.         //level on the other hand supports MultiRun conversions but only from Unicode and this is already handled
  502.         //by the Unicode Converter.
  503.         if( ( *fromTextEncoding == kTextEncodingMultiRun ) || ( *toTextEncoding == kTextEncodingMultiRun ) )
  504.         {
  505.             *converterToUse = kIllegalConverter;
  506.             return;
  507.         }
  508.  
  509.         
  510.         findMapping.unicodeEncoding=kTextEncodingUnicodeDefault;
  511.         findMapping.otherEncoding=*fromTextEncoding;
  512.         
  513.         status = ::QueryUnicodeMappings(kUnicodeMatchOtherBaseMask | kUnicodeMatchOtherVariantMask | kUnicodeMatchOtherFormatMask, 
  514.             &findMapping, 1, &oActualCount, &foundMapping);
  515.         
  516.         if( ( status != noErr && status != kTECArrayFullErr ) || ( oActualCount == 0 ) )
  517.         {
  518.             *converterToUse = kHighLevelConverter;
  519.             return;
  520.         }
  521.         
  522.         findMapping.otherEncoding=*toTextEncoding;
  523.         
  524.         status = ::QueryUnicodeMappings(kUnicodeMatchOtherBaseMask | kUnicodeMatchOtherVariantMask | kUnicodeMatchOtherFormatMask, 
  525.             &findMapping, 1, &oActualCount, &foundMapping);
  526.         
  527.         if( ( status != noErr && status != kTECArrayFullErr ) || ( oActualCount == 0 ) )
  528.         {
  529.             *converterToUse = kHighLevelConverter;
  530.             return;
  531.         }
  532.         
  533.         *converterToUse = kUnicodeConverter;
  534.     }        
  535.  
  536.     
  537. }
  538.  
  539.  
  540.  
  541. // ---------------------------------------------------------------------------------
  542. //        • DoConvertToUnicode
  543. //          Converts a text stream from a specified encoding to Unicode
  544. // ---------------------------------------------------------------------------------
  545. OSStatus
  546. CPPStarterApp::DoConvertToUnicode( TextEncoding unicodeEncoding, UInt32 toUnicodeFlags, TextEncoding fromEncoding, Handle srcH,
  547.                                  ByteCount srcLen, Handle destH, ByteCount &inputRead, ByteCount &unicodeLen, ByteCount maxOutput)
  548. {
  549.     OSStatus            status;
  550.     TextToUnicodeInfo    textToUnicodeInfo;
  551.     UnicodeMapping        theMapping;
  552.     ByteCount            origOutputLen;
  553.  
  554.     
  555.     inputRead=0;
  556.     unicodeLen=0;
  557.     
  558.     
  559.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  560.     if( maxOutput < kMinimumBufferSize )
  561.     {
  562.         maxOutput=kMinimumBufferSize;
  563.         ::HUnlock(destH);
  564.         ::SetHandleSize(destH, maxOutput);
  565.         ::HLock(destH);
  566.     }
  567.     origOutputLen=maxOutput;
  568.  
  569.     char *src=*srcH;
  570.     char *dest=*destH;
  571.  
  572.     /* Create a unicodeMapping holding the specified source encoding and the target unicode encoding */
  573.  
  574.     theMapping.unicodeEncoding = unicodeEncoding;
  575.     theMapping.otherEncoding = fromEncoding;
  576.     theMapping.mappingVersion = kUnicodeUseLatestMapping;
  577.  
  578.     /* Create a conversion context from the specified mapping */
  579.     status=::CreateTextToUnicodeInfo( &theMapping, &textToUnicodeInfo);
  580.     
  581.     if( status )
  582.         Throw_(status);
  583.  
  584.  
  585.     /* Call ConvertFromTextToUnicode as many times as necessary to convert the whole input stream to unicode.
  586.         The output handle will get resized if necessary to accomodate the conversion of the whole input stream */
  587.     do{
  588.         ByteCount    tSourceRead, tUnicodeLen;
  589.         
  590.         status = ::ConvertFromTextToUnicode(textToUnicodeInfo, srcLen, (ConstLogicalAddress) src, toUnicodeFlags,
  591.                 0, nil, nil, nil, maxOutput, &tSourceRead, &tUnicodeLen, (UniCharArrayPtr)dest);
  592.  
  593.         //check to see if we need to adjust our output buffer size.  See discussion of this in ConvertFromMulti method.
  594.         if( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr )
  595.         {
  596.             ResizeOutputHandle( destH, &dest, origOutputLen );
  597.             dest=(char*)( (UInt32)dest + tUnicodeLen);
  598.             maxOutput=origOutputLen+(maxOutput-tUnicodeLen);
  599.  
  600.             src=(char*)( (UInt32)src + tSourceRead);
  601.             srcLen-=tSourceRead;
  602.         }
  603.         
  604.         inputRead+=tSourceRead;
  605.         unicodeLen+=tUnicodeLen;
  606.  
  607.     }while( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr );
  608.     
  609.     ::DisposeTextToUnicodeInfo( &textToUnicodeInfo );
  610.  
  611.     return status;
  612.  
  613. }
  614.  
  615.  
  616.  
  617. // ---------------------------------------------------------------------------------
  618. //        • DoConvertToMultiple
  619. //          Attempts to convert the input Unicode stream to a text stream composed
  620. //          of every single Mac OS Encoding ( derived from the Script ) that is 
  621. //          installed in the machine ( via Language Kits ).
  622. // ---------------------------------------------------------------------------------
  623. OSStatus
  624. CPPStarterApp::DoConvertToMultiple(     TextEncoding unicodeEncoding, UInt32 fromUnicodeFlags, TextEncodingRunHdl &theRuns, Handle srcH, ByteCount srcLen,
  625.                                 Handle destH, ByteCount &inputRead, ByteCount &outputLen, ByteCount maxOutput)
  626. {
  627.     OSStatus                status;
  628.     UnicodeToTextRunInfo    unicodeToTextRunInfo;
  629.     ItemCount                textEncodingRuns;
  630.     ItemCount                oTextEncodingRuns=0;
  631.     UnicodeMapping            mapping={0};
  632.     TextEncodingRunPtr        theRunsPtr;
  633.     ByteCount                origOutputLen;
  634.  
  635.     inputRead=0;
  636.     outputLen=0;
  637.  
  638.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  639.     if( maxOutput < kMinimumBufferSize )
  640.     {
  641.         maxOutput=kMinimumBufferSize;
  642.         ::HUnlock(destH);
  643.         ::SetHandleSize(destH, maxOutput);
  644.         ::HLock(destH);
  645.     }
  646.     origOutputLen=maxOutput;
  647.  
  648.     char *src=*srcH;
  649.     char *dest=*destH;
  650.  
  651.     /* Create a conversion context that maps from the specified version of unicode to 
  652.         every encoding that is currently installed in the system */ 
  653.     mapping.unicodeEncoding=unicodeEncoding;
  654.     status=::CreateUnicodeToTextRunInfo( 0, &mapping, &unicodeToTextRunInfo );
  655.     
  656.     if( status )
  657.         Throw_(status);
  658.     
  659.     /*    Create a handle to hold the text encoding runs that will be derived from converting the
  660.         Unicode stream into a set of Mac OS encoding runs.  Since I don't know what kind of text
  661.         I'm dealing with, but since this application is written to deal with small amounts of text,
  662.         I approximately allocate space for 1 run per every 20 characters of input. If this is
  663.         insufficient, I will adjust the size of the handle.  This is all in the code below.  For
  664.         your own Apps this allocation scheme will surely be flawed.  Especially if you are dealing
  665.         with a lot of text.  */
  666.     textEncodingRuns=( srcLen > 20 ? srcLen/10 : (srcLen > 10 ? srcLen/5 : 2) );
  667.     theRuns = (TextEncodingRunHdl)::NewHandle( sizeof(TextEncodingRun)*textEncodingRuns );
  668.     if( theRuns == 0 )
  669.         Throw_(MemError());
  670.  
  671.     ::HLock( (Handle)theRuns );
  672.     theRunsPtr=*theRuns;
  673.  
  674.     Boolean        ranOutOfSpace=false;
  675.     do{
  676.         ByteCount    tSourceRead, tUnicodeLen;
  677.         
  678.         status = ::ConvertFromUnicodeToTextRun(unicodeToTextRunInfo, srcLen,
  679.          (ConstUniCharArrayPtr) src, fromUnicodeFlags,
  680.                         0, nil, nil, nil, maxOutput, &tSourceRead, &tUnicodeLen, (LogicalAddress)dest,
  681.                         textEncodingRuns, &oTextEncodingRuns, theRunsPtr);
  682.  
  683.     /**********************************************************************************************************
  684.      *    TEC SPECIFIC CODE COMMENT
  685.      *
  686.      *    Here we handle a bit more complex case of kTECOutputBufferFullStatus than in the ConvertFromMulti method
  687.      *    above. The reason being that we need to check if we ran out of encoding run space and of just plain buffer
  688.      *    space.  Both cases are handled below.
  689.      **********************************************************************************************************/
  690.          ranOutOfSpace = (status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr || status == kTECArrayFullErr);
  691.         if( ranOutOfSpace )
  692.         {
  693.             //check to see if we ran out of encoding run buffer.  I know that if I get this error is the encoding run
  694.             //buffer because I did not make use of the offset array parameters in ConvertFromUnicodeToTextRun.  Had
  695.             //I done so, then I would have to check if I ran of offset buffer space, text encoding run buffer space,
  696.             //or both.
  697.             if( status == kTECArrayFullErr )
  698.             {    
  699.                 ResizeOutputHandle(  (Handle)theRuns, &((char*)theRunsPtr), (textEncodingRuns*sizeof(TextEncodingRun)) );
  700.                 
  701.                 maxOutput-=tUnicodeLen;
  702.             }
  703.             else    //it must have been that we ran out of buffer space.  NOTE, there is the possibility that
  704.             {        //we run out of both output buffer and encoding run buffer space.  That is unlikely, but if
  705.                     //it does happen to be the case, when we execute ConvertFromUnicodeToTextRun it will again
  706.                     //return a status error indicating that not enough buffer space for one or the other is
  707.                     //available, at that point we'll just adjust it.
  708.             
  709.                 ResizeOutputHandle( destH, &dest, origOutputLen );
  710.                 maxOutput=origOutputLen+(maxOutput-tUnicodeLen);
  711.             }
  712.             
  713.             dest=(char*)( (UInt32)dest + tUnicodeLen);
  714.             
  715.             src=(char*)( (UInt32)src + tSourceRead);
  716.             srcLen-=tSourceRead;
  717.         }
  718.         
  719.         //Adjust our encoding run array if this is not the first time we've gone through the loop.  We
  720.         //need to do this because ConvertFromUnicodeToTextRun encoding run offsets are zero based from
  721.         //the output stream it produces.  The second through nth time we call ConvertFromUnicodeToTextRun,
  722.         //the input/output streams are no longer zero based as far as the original caller to DoConvertToMultiple
  723.         //is concerned, so we need to adjust those offsets accordingly.
  724.         if( outputLen != 0 )
  725.         {
  726.             for( int runIndex=0; runIndex<oTextEncodingRuns; runIndex++)
  727.                 (theRunsPtr[runIndex]).offset+=outputLen;
  728.         }
  729.         
  730.         theRunsPtr+=oTextEncodingRuns;
  731.         
  732.         inputRead+=tSourceRead;
  733.         outputLen+=tUnicodeLen;
  734.  
  735.     }while( ranOutOfSpace );
  736.  
  737.     /**********************************************************************************************************
  738.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  739.      **********************************************************************************************************/
  740.  
  741.     
  742.     ::HUnlock( (Handle)theRuns );
  743.     ::SetHandleSize( (Handle)theRuns, ::GetHandleSize( (Handle)theRuns) - ( (textEncodingRuns-oTextEncodingRuns)*sizeof(TextEncodingRun) ) );
  744.     
  745.     ::DisposeUnicodeToTextRunInfo( &unicodeToTextRunInfo );
  746.  
  747.     return status;
  748.  
  749. }
  750.  
  751. // ---------------------------------------------------------------------------------
  752. //        • DoConvertToEncoding
  753. //        Converts a Unicode stream to a stream of text in the specified encoding
  754. // ---------------------------------------------------------------------------------
  755. OSStatus
  756. CPPStarterApp::DoConvertToEncoding(    TextEncoding unicodeEncoding, UInt32 fromUnicodeFlags, TextEncoding    toEncoding, Handle srcH, ByteCount srcLen,
  757.                                 Handle destH, ByteCount &inputRead, ByteCount &outputLen, ByteCount maxOutput)
  758. {
  759.     OSStatus            status;
  760.     UnicodeToTextInfo    unicodeToTextInfo;
  761.     UnicodeMapping        theMapping;
  762.     ByteCount            origOutputLen;
  763.  
  764.     
  765.     
  766.     inputRead=0;
  767.     outputLen=0;
  768.  
  769.     
  770.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  771.     if( maxOutput < kMinimumBufferSize )
  772.     {
  773.         maxOutput=kMinimumBufferSize;
  774.         ::HUnlock(destH);
  775.         ::SetHandleSize(destH, maxOutput);
  776.         ::HLock(destH);
  777.     }
  778.     origOutputLen=maxOutput;
  779.  
  780.     char *src=*srcH;
  781.     char *dest=*destH;
  782.  
  783.  
  784.     /* Create a unicodeMapping holding the specified source encoding and the target unicode encoding */
  785.  
  786.     theMapping.unicodeEncoding = unicodeEncoding;
  787.     theMapping.otherEncoding = toEncoding;
  788.     theMapping.mappingVersion = kUnicodeUseLatestMapping;
  789.     
  790.     /* Create a conversion context from the specified mapping */
  791.     status=::CreateUnicodeToTextInfo( &theMapping, &unicodeToTextInfo);
  792.     if( status )
  793.         Throw_(status);
  794.  
  795.     /* Call ConvertFromUnicodeToText as many times as necessary to convert the whole unicode stream.
  796.         The output handle will get resized if necessary to accomodate the conversion of the whole input stream */
  797.     do{
  798.         ByteCount    tSourceRead, tUnicodeLen;
  799.         
  800.         status = ::ConvertFromUnicodeToText(unicodeToTextInfo, srcLen, (ConstUniCharArrayPtr) src, fromUnicodeFlags,
  801.                         0, nil, nil, nil, maxOutput, &tSourceRead, &tUnicodeLen, (LogicalAddress)dest);
  802.  
  803.         //check to see if we need to adjust our output buffer size.  See discussion of this in ConvertFromMulti method.
  804.         if( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr )
  805.         {
  806.             ResizeOutputHandle( destH, &dest, origOutputLen );
  807.             dest=(char*)( (UInt32)dest + tUnicodeLen);
  808.             maxOutput=origOutputLen+(maxOutput-tUnicodeLen);
  809.  
  810.             src=(char*)( (UInt32)src + tSourceRead);
  811.             srcLen-=tSourceRead;
  812.         }
  813.         
  814.         inputRead+=tSourceRead;
  815.         outputLen+=tUnicodeLen;
  816.  
  817.     }while( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr );
  818.     
  819.     ::DisposeUnicodeToTextInfo( &unicodeToTextInfo );
  820.  
  821.     return status;
  822.  
  823. }
  824.  
  825.  
  826. // ---------------------------------------------------------------------------------
  827. //        • DoConvertUsingHLC
  828. //        Converts a text stream from one encoding to another using the Text Encoding
  829. //        Converter.
  830. // ---------------------------------------------------------------------------------
  831. OSStatus
  832. CPPStarterApp::DoConvertUsingHLC(    TextEncoding fromTextEncoding, Handle fromTextH, ByteCount fromTextLen,
  833.                                     TextEncoding toTextEncoding,  Handle toTextH, ByteCount toTextLen,
  834.                                      ByteCount &inputRead, ByteCount &outputLen )
  835. {
  836.     OSStatus        status;
  837.     TECObjectRef    newEncodingConverter;
  838.     ByteCount        origOutputLen;
  839.     Boolean            needsToFlush=true;
  840.     
  841.     inputRead=0;
  842.     outputLen=0;
  843.     
  844.     if( fromTextLen == 0 )
  845.         return noErr;
  846.         
  847.     /* Resize our output buffer if necessary to the minimum buffer we recommended earlier*/
  848.     if( toTextLen < kMinimumBufferSize )
  849.     {
  850.         toTextLen=kMinimumBufferSize;
  851.         ::HUnlock(toTextH);
  852.         ::SetHandleSize(toTextH, toTextLen);
  853.         ::HLock(toTextH);
  854.     }
  855.     origOutputLen=toTextLen;
  856.  
  857.     char *fromText=*fromTextH;
  858.     char *toText=*toTextH;
  859.  
  860.     /* Create a conversion object based on the source and destination encodings */
  861.     status = ::TECCreateConverter(&newEncodingConverter, fromTextEncoding,  toTextEncoding);
  862.     if( status )
  863.         Throw_(status);
  864.  
  865.     /**********************************************************************************************************
  866.      *    TEC SPECIFIC CODE COMMENT
  867.      *
  868.      *    Converting text using the Text Encoding Converter is no different than using the Unicode Converter.
  869.      *    However, there is one thing to watch out for.  That is, some converters may have some output left over
  870.      *    even when there is no more input to process.  So instead of calling TECConvertText, we call TECFlushText
  871.      *    to extract any other text that converter plugin may have in it's internal buffers.
  872.      **********************************************************************************************************/
  873.  
  874.     do{
  875.         ByteCount    tSourceRead, tUnicodeLen;
  876.         
  877.         /* If fromTextLen > 0 then we have some characters in the input stream which haven't been processed by
  878.             the converter, so call TECConvertText.  Otherwise, we've exhausted the input stream, so we just need
  879.             to flush out the rest of the converted stream from TEC's internal buffers.  Hence, we call  TECFlushText.
  880.             TECFlushText will be called at least once.  Could be called more depending on how much buffer space is left */
  881.         if( fromTextLen > 0 )
  882.             status = ::TECConvertText( newEncodingConverter, (ConstTextPtr) fromText,  fromTextLen, &tSourceRead, (TextPtr)toText,  toTextLen,  &tUnicodeLen);
  883.         else
  884.         {
  885.             status=::TECFlushText(newEncodingConverter, (TextPtr) toText, toTextLen, &tUnicodeLen);
  886.             needsToFlush=false;
  887.         }
  888.  
  889.         
  890.         if( fromTextLen > 0 )        //only adjust inputRead if not being called from TECFlushText
  891.             inputRead+=tSourceRead;
  892.             
  893.         outputLen+=tUnicodeLen;
  894.  
  895.         //check to see if we need to adjust our output buffer size.  This adjustment is no different from
  896.         //what we have seen in the Convert methods above.  We just take into consideration that we might
  897.         //be getting called from a TECFlushText so no adjustments need to be made for the input buffer
  898.         //or input length.
  899.         if( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr )
  900.         {
  901.             ResizeOutputHandle( toTextH, &toText, origOutputLen );
  902.             toTextLen=origOutputLen+(toTextLen-tUnicodeLen);
  903.             
  904.             //It could happen that we set the needsToFlush flag to false prematurely, so reset it.
  905.             if(needsToFlush == false )
  906.                 needsToFlush=true;
  907.         }
  908.         else
  909.             toTextLen-=tUnicodeLen;
  910.  
  911.         toText=(char*)( (UInt32)toText + tUnicodeLen);
  912.         
  913.         if( fromTextLen > 0 )    //only adjust src/fromTextLen if not being called from TECFlushText
  914.         {
  915.             fromText=(char*)( (UInt32)fromText + tSourceRead);
  916.             fromTextLen-=tSourceRead;
  917.         }
  918.  
  919.     }while( status == kTECOutputBufferFullStatus || status == kTECBufferBelowMinimumSizeErr || needsToFlush);
  920.  
  921.  
  922.     /**********************************************************************************************************
  923.      *    END TEC SPECIFIC CODE COMMENTED BLOCK
  924.      **********************************************************************************************************/
  925.  
  926.     ::TECDisposeConverter( newEncodingConverter);
  927.  
  928.     return status;
  929.  
  930. }
  931.  
  932. // ---------------------------------------------------------------------------------
  933. //        • DoConvert
  934. //        
  935. //        This method gets called when a conversion needs to take place that isn't 
  936. //        Styled Text in origin.  It does not contain much Text Encoding Converter
  937. //        related features in it.  It is just a hub that serves to determine which
  938. //        conversion needs to take place.
  939. // ---------------------------------------------------------------------------------
  940.  
  941. OSStatus
  942. CPPStarterApp::DoConvert(    const Handle fromHexText, UInt32 fromLen, UInt32 fromEncoding,
  943.                             Handle toHexText, ByteCount &inputRead, ByteCount &outputLen, ByteCount &toLen, 
  944.                             UInt32 toEncoding, TextEncodingRunHdl &theRuns, 
  945.                             UInt32    fromUnicodeFlags, UInt32 toUnicodeFlags,
  946.                             Boolean wantHexOutput)
  947. {
  948.     volatile OSStatus    status=noErr;
  949.     volatile Handle        localFromText=0L;
  950.     volatile Handle        localToText=0L;
  951.  
  952.      EDebugAction    lDebugThrow=gDebugThrow;
  953.     EDebugAction    lDebugSignal=gDebugSignal;
  954.     
  955.     SetDebugThrow_(debugAction_Nothing);
  956.     SetDebugSignal_(debugAction_Nothing);
  957.  
  958.     Try_
  959.     {
  960.         Boolean        legalHexStr;
  961.         ByteCount    toHexLen;
  962.         ByteCount    localFromLen;
  963.         
  964.         TextEncoding    fromTextEncoding;
  965.         TextEncoding    toTextEncoding;
  966.         int                converterToUse;
  967.         
  968.         // Initialize some of our byte count output parameters
  969.         inputRead = 0;
  970.         outputLen = 0;
  971.         toLen=0;
  972.         
  973.         //Create a local fromText and use it to hold the from string consisting of the 
  974.         //converted hex string
  975.         
  976.         localFromText=::NewHandle( fromLen*2 );        
  977.         FailNIL_(localFromText);
  978.         
  979.         //Convert our string from Hex
  980.         ::HLock( fromHexText );
  981.         ::HLock( localFromText );
  982.         legalHexStr=FromHexToString( (StringPtr)*fromHexText, fromLen, (StringPtr)*localFromText, localFromLen );
  983.         if( !legalHexStr )
  984.         {
  985.             ::BlockMove( *fromHexText, *localFromText, fromLen );
  986.             localFromLen = fromLen;
  987.         }
  988.         
  989.         ::HUnlock( localFromText );
  990.         ::SetHandleSize( localFromText, localFromLen );
  991.         ::HLock( localFromText );
  992.  
  993.         ::HUnlock( fromHexText );
  994.         
  995.         toHexLen = ::GetHandleSize(toHexText);
  996.  
  997.         // Determine if the Unicode Converter can handle the input and output encodings.  If so, then use the Unicode
  998.         // Converter as a Hub to perform the conversion.  Otherwise, use the High Level Converter.
  999.         ResolveConversionParams( fromEncoding, &fromTextEncoding, toEncoding, &toTextEncoding, &converterToUse );
  1000.         if( converterToUse == kUnicodeConverter )
  1001.         {
  1002.             //make a copy of the toText handle
  1003.             localToText = toHexText;
  1004.             ::HandToHand(&localToText);
  1005.             ThrowIfMemError_();
  1006.             
  1007.             //Convert from encoding x to unicode -- if already unicode, just copy the string
  1008.             if( !IsUnicode(fromTextEncoding)    )
  1009.             {
  1010.                 TextEncoding    unicodeEncoding;
  1011.                 
  1012.                 ::HLock( localToText );
  1013.                 
  1014.                 unicodeEncoding =IsUnicode(toTextEncoding) ? toTextEncoding : kTextEncodingUnicodeDefault;
  1015.                 status=DoConvertToUnicode(    unicodeEncoding, toUnicodeFlags, 
  1016.                                             fromTextEncoding, localFromText, localFromLen,
  1017.                                             localToText, inputRead, outputLen, ::GetHandleSize(localToText));
  1018.                 fromTextEncoding = unicodeEncoding;
  1019.             }
  1020.             else
  1021.             {
  1022.                 ::HLock( localToText );
  1023.                 ::BlockMove( *localFromText, *localToText, localFromLen );
  1024.                 inputRead=0;
  1025.                 outputLen=localFromLen;
  1026.             }
  1027.             if(status && status!=kTECUsedFallbacksStatus)
  1028.                 Throw_( status );
  1029.                 
  1030.             //Convert from unicode to encoding x -- if already encoding x, just copy the string
  1031.             if( !IsUnicode( toTextEncoding)  )
  1032.             {
  1033.                 ::HLock( toHexText );
  1034.                 
  1035.                 if( toTextEncoding != kTextEncodingMultiRun  )
  1036.                     status=DoConvertToEncoding(    fromTextEncoding, fromUnicodeFlags, toTextEncoding, localToText, outputLen, toHexText,
  1037.                                             inputRead, outputLen, toHexLen);
  1038.                 else
  1039.                     status=DoConvertToMultiple( fromTextEncoding, fromUnicodeFlags, theRuns, localToText, outputLen, 
  1040.                                                     toHexText, inputRead, outputLen, toHexLen);
  1041.                 
  1042.                 ::BlockMove( *toHexText, *localToText, outputLen );
  1043.                 
  1044.                 toHexLen = ::GetHandleSize(toHexText);            //toHextText's size might have changed during the conversion process        
  1045.             }
  1046.             
  1047.         }
  1048.         else if( converterToUse == kHighLevelConverter )
  1049.         {
  1050.             //make a copy of the toText handle
  1051.             localToText = toHexText;
  1052.             ::HandToHand(&localToText);
  1053.             ThrowIfMemError_();
  1054.  
  1055.             ::HLock( localToText );
  1056.             
  1057.             status=DoConvertUsingHLC(    fromTextEncoding, localFromText, localFromLen,
  1058.                                         toTextEncoding, localToText, ::GetHandleSize(localToText), inputRead, outputLen);
  1059.                                         
  1060.         }
  1061.         else // converterToUse == kIllegalConverter
  1062.         {
  1063.             ::SetHandleSize( localToText, 0 );
  1064.             outputLen=0;
  1065.             inputRead=0;
  1066.             status=paramErr;
  1067.             ::ParamText("\pConversion requested is illegal or cannot be handled by this App","\p","\p","\p");
  1068.             ::Alert(kSimpleAlert, NULL);
  1069.         }
  1070.         
  1071.         if( wantHexOutput )
  1072.         {
  1073.             //When converting to Unicode, we will be converting the string to hex so that the hex representation
  1074.             //for 2 bytes is together plus a space separating it from the next 2 byte sequence.  When converting
  1075.             //to anything else, we will put a space between every byte.
  1076.             //Therefore, we need to figure out if we have enough space in our destination buffer.
  1077.             UInt8    clumpSize = (IsUnicode(toTextEncoding)) ? 2 : 1;
  1078.             UInt32    estOutputLen =  outputLen*2 + outputLen/clumpSize + outputLen%clumpSize ;
  1079.             if( toHexLen < estOutputLen )
  1080.             {
  1081.                 ::HUnlock( toHexText );
  1082.                 SetHandleSize( toHexText, estOutputLen );
  1083.                 ThrowIfMemError_();
  1084.                 
  1085.                 ::HLock( toHexText );
  1086.             }
  1087.             
  1088.             BufToHex( (StringPtr)*localToText, (StringPtr)*toHexText, outputLen, toLen, clumpSize );
  1089.  
  1090.             //Delete the runs handle since they don't make any sense in Hex
  1091.             if( theRuns )
  1092.             {
  1093.                 ::DisposeHandle( (Handle)theRuns );
  1094.                 theRuns=0;
  1095.             }
  1096.         }
  1097.         else
  1098.         {
  1099.             //resize the handle in the event that our outputLen is bigger or smaller
  1100.             ::HUnlock( toHexText );
  1101.             ::SetHandleSize( toHexText, outputLen );
  1102.             ::HLock( toHexText );
  1103.             
  1104.             ::BlockMove( *localToText, *toHexText, outputLen );
  1105.             toLen=outputLen;
  1106.         }
  1107.             
  1108.             
  1109.         if(status && status!=kTECUsedFallbacksStatus)
  1110.             Throw_(status);
  1111.         
  1112.         
  1113.     }
  1114.     Catch_(xErr)
  1115.     {
  1116.         ::SetHandleSize( toHexText, toLen );
  1117.         ::SysBeep(0);
  1118.         status = xErr;
  1119.     }
  1120.     EndCatch_
  1121.     
  1122.     if( localFromText )
  1123.         ::DisposeHandle(localFromText);
  1124.     if( localToText )
  1125.         ::DisposeHandle(localToText);
  1126.         
  1127.     ::HUnlock( toHexText );
  1128.     
  1129.     SetDebugThrow_(lDebugThrow);
  1130.     SetDebugSignal_(lDebugSignal);
  1131.         
  1132.     return status;
  1133. }
  1134.  
  1135.